var BASE_STOCK = [
	"近3日平均成交额前240名",
	"前10日主力净流入前200且市值大于100亿且成交额大于1亿",
	"热点前200名且成交额大于10亿",
	"净资产收益率大于10%；营收增长≥10%；成交额大于10亿",
	"近3日平均成交额大于5000万场内非货币基金",
	"一级行业龙头",
	"二级行业龙头",
	"三级行业龙头",
	//"近3日跑赢大盘",
	//"成交额大于1.5亿",
	//"近20日平均成交额大于1.5亿",
	//"创20日新高;成交额大于1.5亿;",
	"中证800",
	"中证流通"
];

var BASE_FILTER = [
	"({收位置} > 0.8) && ({收位置} < 1.6) && ({柱体(%)} > 0)",
];

var DATE_LIST = [
	"20210309",
	"20210218",
	"20210113",
	"20201225",
	"20201110",
	"20201110",
	"20200930",
	"20200901",
	"20200730",
	"20200713",
	"20200615",
	"20200525",
	"20200324",
];

// 指数
var INDEX = [
	["sh000986","中证全指能源指数"],
	["sh000987","中证全指原材料指数"],
	["sh000988","中证全指工业指数"],
	["sh000989","中证全指可选消费指数"],
	["sh000990","中证全指主要消费指数"],
	["sh000991","中证全指医药卫生指数"],
	["sh000992","中证全指金融地产指数"],
	["sh000993","中证全指信息技术指数"],
	["sh000994","中证全指电信业务指数"],
	["sh000995","中证全指公用事业指数"],
];

function extremum(arr, pos, num, key) {
	if (null == pos) {
		pos = arr.length - 1;
	}

	if (null == num) {
		num = 20;
	}

	if (null == key) {
		key = 'close';
	}
	var beg = pos - num + 1;
	if (beg < 0) {
		beg = 0;
	}
	var min = Number.MAX_VALUE, max = 0, minPos = 0, maxPos = 0;
	for (var i = beg; i <= pos; i++){
		var e = arr[i][key];
		if (e > max) {
			max = e;
			maxPos = i;
		}

		if (e < min) {
			min = e;
			minPos = i;
		}
	}

	return {
		min : min,
		max : max,
		minPos : minPos,
		maxPos : maxPos,
	}
}

// 合并K线
function combKLine(arr, pos, num) {
    if (null == pos) {
        pos = arr.length - 1;
    }
    if (pos >= arr.length) {
		pos = arr.length - 1;
		return {
			open : arr[pos].close,
			close : arr[pos].close,
			high : arr[pos].close,
			low : arr[pos].close,
			begin : 0,
			end : 0,
		};
	}
    if ((null == num) || (num < 0)) {
        num = 3;
    }
    var open = pos - num;
    if (open < 0) {
        open = 0;
    }

    var ret = {
        open : arr[open + 1].open,
        close : arr[pos].close,
        high : 0,
        low : 100000000
    };

    for (var i = open + 1; i <= pos; i++) {
        var e = arr[i];
        if (ret.high < e.high) {
            ret.high = e.high;
        }
        if (ret.low > e.low) {
            ret.low = e.low;
        }
    }

    var K = KType(ret, arr[open]);
    ret.begin = K.begin;
    ret.end = K.end;
    return ret;
}

function KType(d0, d1) {
    var ret = {
        begin : 0,
        end : 0
    };

    var open = (d0.open - d0.low) / (d0.high - d0.low);
    var close = (d0.close - d0.low) / (d0.high - d0.low);

    // 高开新高，高开吞实体，高开孕位
    if (d0.open >= d1.close) {
        if (d0.open >= d1.high) {
            ret.begin = 3;
        } else if (d0.open >= d1.open) {
            ret.begin = 2;
        } else {
            ret.begin = 1;
        }
    }
    // 低开孕位，低开吞实体，低开新低
    else {
        if (d0.open < d1.low) {
            ret.begin = -3;
        } else if (d0.open < d1.open) {
            ret.begin = -2;
        } else {
            ret.begin = -1;
        }
    }
    ret.begin += open;

    // 收盘阳线新高，收盘阳线高点新高，收盘阳线涨无新高，收盘阳线跌
    if (d0.close >= d0.open) {
        if (d0.close >= d1.high) {
            ret.end = 4;
        } else if (d0.high >= d1.high) {
            ret.end = 3;
        } else if (d0.close >= d1.close) {
            ret.end = 2;
        } else {
            ret.end = 1;
        }
    }
    // 收盘阴线涨，收盘跌未创新低，收盘跌低点新低，收盘新低
    else {
        if (d0.close >= d1.close) {
            ret.end = -1;
        } else if (d0.low >= d1.low) {
            ret.end = -2;
        } else if (d0.close >= d1.low) {
            ret.end = -3;
        } else {
            ret.end = -4;
        }
    }
    ret.end += close;

    return ret;
}

function linear(arr, pos, num, key){
	/*
	y = a * x + b
	a = sum (xi - xv)(yi - yv) / sum (xi - xv)(xi - xv)
	b = yv - a * xv
	*/
	if (null == pos) {
		pos = arr.length - 1;
	}

	if (null == num) {
		num = 5;
	}

	if (null == key) {
		key = 'close';
	}

	var sum_x = 0;
	var sum_y = 0;
	for (var i = pos - num + 1; i <= pos; i++) {
		sum_x += i - pos;
		sum_y += arr[i][key];
	}
	var xv = sum_x / num;
	var yv = sum_y / num;

	var numerator = 0;
	var denominator = 0;

	for (var i = pos - num + 1; i <= pos; i++) {
		var x = i - pos - xv;
		var y = arr[i][key] - yv;
		numerator += x * y;
		denominator += x * x;
	}

	var slope = numerator / denominator;
	var diff = yv - (slope * xv);
	var next = slope * (1) + diff;

	return {
		slope : slope,
		diff : diff,
		next : next
	}
}

function trend(data, pos, num) {
	if (null == pos) {
		pos = data.length - 1;
	}

	if (null == num) {
		num = 6;
	}

	var cnt = num;
	if (pos < num) {
		cnt = pos + 1;
	}

	var avHr = 0;
	var avLr = 0;
	for (var i = pos - cnt + 2; i <= pos; i++) {
		var e = data[i];
		var e1 = data[i-1];
		var hr = (e.high - e1.high)*100/e1.high;
		var lr = (e.low - e1.low)*100/e1.low;
		avHr += hr;
		avLr += lr;
	}
	avHr = avHr / (cnt-1);
	avLr = avLr / (cnt-1);
	return [avLr, avHr];
}

function avg(arr, pos, num, key) {
    var sum = 0;
    for (var i = pos - num + 1; i <= pos; i++) {
        sum += arr[i][key];
    }
    return sum/num;
}

// 正态分布近似计算
function getProbability(x, u, q) {
    var a = 4 / (Math.sqrt(2 * Math.PI) * q);
    var e = Math.exp(a * (x - u));
    return e / (1 + e);
}

// 平均增长率
function increaseRate(p, win, lose) {
    return Math.pow((1+win), p) * Math.pow((1-lose), (1-p));
}

function cut(d, abs) {
    if (null == abs) {
        abs = 10;
    }
    if (d > abs) {
        return abs;
    }
    if (d < 0-abs) {
        return 0-abs;
    }
    return d;
}

/////////////////////////////////////////

var COLUMN_NAME = null;
function init_name() {
    COLUMN_NAME = {
        "id":"股票",
        "name":"股票",
        "time":"日期",
        "open":"开盘",
        "close":"收盘",
        "high":"最高",
        "low":"最低",
        "transactions":"成交额(万)",
        "turnover":"换手率(%)",
        "amplitude":"振幅(%)"
    };
    for (var f in FACTOR) {
        for (var i in FACTOR[f]) {
            var e = FACTOR[f][i];
            for (var j in e.name){
                COLUMN_NAME[e.key[j]] = e.name[j];
				COLUMN_NAME[e.key[j] + "-N"] = e.name[j] + "-N";
            }
        }
    }
}

function getColumn(type) {
    if (null == COLUMN_NAME) {
        init_name();
    }
    var kline = ["open","close","high","low","transactions","turnover","amplitude"];
	var base = ["name","time","amplitude"];
	var factor = [];
	var show = [];
	for (var f in FACTOR) {
		for (var i in FACTOR[f]) {
			var e = FACTOR[f][i];
			if (null == e.key) {
				continue;
			}
			factor = factor.concat(e.key);
			if (null != e.show) {
				show = show.concat(e.show);
			} else {
				show = show.concat(e.key);
			}
		}
	}
	if ("factor" == type) {
		return factor;
	}
	if ("show" == type) {
		return base.concat(show);
	}
	if ("check" == type) {
		return show;
	}
	return base.concat(factor, kline);
}

function formatData_Level(row, pos, level, prev) {
	if (null == pos) {
		pos = row.data.length - 1;
	}

	if (null == row.data[pos]) {
		return;
	}

	if (null == row.data[pos].id) {
		var name = row.name;
		if (row.name.indexOf(row.id) < 0) {
			name = row.id + " " + (row.name || "");
		}
		row.data[pos].id = row.id;
		row.data[pos].name = name;
	}

	var key = [];
	for (var i in FACTOR[level]) {
		var e = FACTOR[level][i];
		if (null == e.key) {
			continue;
		}
		try {
			var r = e.func(row.data, pos, prev);
			for (var j = 0; j < e.key.length; j++) {
				//row.data[pos][e.key[j]] = parseFloat(parseFloat(r[j]).toFixed(2));
				row.data[pos][e.key[j]] = Math.round(r[j]*100)/100;
				key.push(e.key[j]);
			}
		} catch (err) {
			console.log(err, [e, row, pos, level, prev]);
		}
	}

	row.data[pos].url = getUrl(row.id);
	row.data[pos].currentPage = 1;
	row.data[pos].key = key;
	row.data[pos].data = row.data;
	row.data[pos].index = row.index;
}

function formatData(row, pos, cnt, prev) {
	if (null == pos) {
		pos = row.data.length - 1;
	}
	if (null == cnt) {
		cnt = 1;
	}
	if (null == prev) {
		prev = 1;
	}

	for (var level in FACTOR) {
		for (var i = pos - cnt + 1; i <= pos; i++) {
			formatData_Level(row, i, level, prev);
		}
	}
	return row.data.slice(pos - cnt + 1, pos+1);
}

function parseData(rows, prev, calcCnt) {
    var data = [];
    var column = getColumn("show");
    var check = getColumn("check");
    for (var j = 0; j < check.length; j++) {
        var key = check[j];
        column.push(key + "-N");
    }
    for (var i = 0; i < rows.length; i++) {
        var arr = formatData(rows[i], null, calcCnt + prev, prev);
        for (var r = prev; r < arr.length; r++) {
            for (var j = 0; j < check.length; j++) {
                var key = check[j];
                arr[r][key + "-N"] = arr[r-prev][key];
            }
            data.push(arr[r]);
        }
    }

    return {
        column : column,
        data : data
    }
}

/////////////////////////////////////
var FACTOR = [
	// LV1
	[
		{
			name : ["标准差","平均值","标准差(%)","收方差位置","开方差位置","平均换手","量比"],
			key : ["Q","AV","Q%","PC","PO","AVT","V0"],
			show : ["Q%","PC","PO","AVT","V0"],
			func : function(data, pos) {
				if (null == pos) {
					pos = data.length - 1;
				}

				var cnt = 20;
				if (pos < 20) {
					cnt = pos + 1;
				}

				var avg = 0;
				var avgV = 0;
				for (var i = pos - cnt + 1; i <= pos; i++) {
					var e = data[i];
					avg += e.high + e.low;
					avgV += e.turnover;
				}
				avg = avg / (2 * cnt);
				avgV = avgV / cnt;

				var s = 0;
				for (var i = pos - cnt + 1; i <= pos; i++) {
					var e = data[i];
					s += (e.high-avg)*(e.high-avg) + (e.low-avg)*(e.low-avg);
				}
				s = Math.sqrt(s / (2 * cnt - 1));
				var d0 = data[pos];
				return [s, avg, cut(s * 100/avg, 30),
					(d0.close-avg)/s, (d0.open-avg)/s, cut(avgV,30),
					cut(d0.turnover/avgV,5)
				];
			}
		},
		/*
		{
			name : ["K","D","J","量K","量D","量J"],
			key : ["K","D","J","VK","VD","VJ"],
			show : ["K","D","J","VK","VD","VJ"],
			func : function(data, pos, prev) {
				if (null == pos) {
					pos = data.length - 1;
				}

				var N = 10;
				var high = extremum(data, pos, N, 'high');
				var low = extremum(data, pos, N, 'low');
				var ex = extremum(data, pos, N, 'trafnsactions');

				var d0 = data[pos];
				var d1 = data[pos-1];
				var RSV = (d0.close - low.min) * 100 / (high.max - low.min);
				var K1 = (null == d1.K ? 50 : d1.K);
				var D1 = (null == d1.D ? 50 : d1.D);
				var K = (2 * K1 / 3) + RSV / 3;
				var D = (2 * D1 / 3) + K / 3;
				var J = 3 * K - 2 * D;
				var VRSV = (d0.transactions - ex.min) * 100 / (ex.max - ex.min);
				var VK1 = (null == d1.VK ? 50 : d1.VK);
				var VD1 = (null == d1.VD ? 50 : d1.VD);
				var VK = (2 * VK1 / 3) + VRSV / 3;
				var VD = (2 * VD1 / 3) + VK / 3;
				var VJ = 3 * VK - 2 * VD;
				return [K,D,J,VK,VD,VJ];
			}
		},
		 */
		/*
		{
			name : ["涨幅(%)","柱体(%)","低点涨(%)","高点涨(%)","低(%)","高(%)","K线","量比","N日涨"],
			key : ["R1","U","LR","HR","CLR","CHR","K0","V0","RN"],
			func : function(data, pos, prev){
				if (null == pos) {
					pos = data.length - 1;
				}
				//var t = trend(data, pos-1);
				var d0 = data[pos];
				var d1 = data[pos-1];
				var dN = data[pos-prev];

				var lc = ((d0.low - d1.low)*100/d1.low);
				var hc = ((d0.high - d1.high)*100/d1.high);
				var high = extremum(data, pos, prev, 'high');
				var low = extremum(data, pos, prev, 'low');
				var p = increaseRate(0.5, (high.max - dN.close)/dN.close, (dN.close - low.min)/dN.close);

				return [
				    cut((d0.close - d1.close)*100/d1.close),
					cut((d0.close - d0.open)*100/d0.open),
                    cut(lc), cut(hc),
					cut(((d0.low - d1.close)*100/d1.close)), cut(((d0.high - d1.close)*100/d1.close)),
					(d0.close - d0.low)*10/(d0.high - d0.low),
					d0.turnover / d0.AVT,
					cut((p-1)*100),
					cut((d0.close - dN.close)*100/dN.close)
				];
			}
		},
		 */
		{
			name : ["开盘K","收盘K","2日开盘K","2日收盘K","3日开盘K","3日收盘K","5日开盘K","5日收盘K",
				"开波动位置","收波动位置","2日开波动位置","2日收波动位置","3日开波动位置","3日收波动位置","5日开波动位置","5日收波动位置",
				"当日期望","1日后期望","2日后期望","3日后期望","5日后期望"
			],
			key : ["OK","CK","OK2","CK2","OK3","CK3","OK5","CK5",
				"OP","CP","2OP","2CP","3OP","3CP","5OP","5CP",
				"E0","E1","E2","E3","E5",
			],
            show : ["OK","CK","OK2","CK2","OK3","CK3","OK5","CK5",
				"OP","CP","2OP","2CP","3OP","3CP","5OP","5CP",
				"E0","E1","E2","E3","E5",
			],
			func : function(data, pos, prev){
				if (null == pos) {
					pos = data.length - 1;
				}
				var d0 = data[pos];
				var d1 = data[pos-1]||d0;

				var k1 = combKLine(data, pos, 1);
				var k2 = combKLine(data, pos, 2);
                var k3 = combKLine(data, pos, 3);
                var k5 = combKLine(data, pos, 5);

                var next = pos + prev;
                if (next >= data.length - 1) {
                    next = data.length - 1;
                }

                //var kn = combKLine(data, next, next-pos);
				var nk1 = combKLine(data, pos + 1, 1);
				var nk2 = combKLine(data, pos + 2, 2);
				var nk3 = combKLine(data, pos + 3, 3);
				var nk5 = combKLine(data, pos + 5, 5);
				return [k1.begin, k1.end, k2.begin, k2.end, k3.begin, k3.end, k5.begin, k5.end,
					(d0.open - d0.low) / (d0.high - d0.low),
					(d0.close - d0.low) / (d0.high - d0.low),
					(k2.open - k2.low) / (k2.high - k2.low),
					(k2.close - k2.low) / (k2.high - k2.low),
					(k3.open - k3.low) / (k3.high - k3.low),
					(k3.close - k3.low) / (k3.high - k3.low),
					(k5.open - k5.low) / (k5.high - k5.low),
					(k5.close - k5.low) / (k5.high - k5.low),
					cut((((d0.high + d0.low + d0.close)/(d1.close*3))-1)*100),
					cut((((nk1.high + nk1.low + nk1.close)/(d0.close*3))-1)*100),
					cut((((nk2.high + nk2.low + nk2.close)/(d0.close*3))-1)*100,15),
					cut((((nk3.high + nk3.low + nk3.close)/(d0.close*3))-1)*100,20),
					cut((((nk5.high + nk5.low + nk5.close)/(d0.close*3))-1)*100,20),
				];
			}
		},
	],
	// LV2
	[
		/*
		{
			name : ["价位","量位","低价距离","高价距离","低量距离","高量距离"],
			key : ["PP","VP","LPD","HPD","LVD","HVD"],
			func : function(data, pos) {
				var d0 = data[pos];
                var high = extremum(data, pos, 20, 'high');
                var low = extremum(data, pos, 20, 'low');
                var vol = extremum(data, pos, 10, 'transactions');
				return [
				    cut((d0.close - low.min) * 10 / (high.max - low.min)),
                    cut((d0.transactions - vol.min) * 10 / (vol.max - vol.min)),
                    pos - low.minPos, pos - high.maxPos,
                    pos - vol.minPos, pos - vol.maxPos,
                ];
			}
		},
		*/
		{
			name: ["标准差斜率(%)", "均值斜率(%)", "标准差Max(%)", "标准差Min(%)", "量差"],
			key: ["QS", "AVS", "QMax", "QMin", "DV"],
			show : ["QS", "AVS", "DV"],
			func: function (data, pos) {
				if (null == pos) {
					pos = data.length - 1;
				}

				var d0 = data[pos];
				var d1 = data[pos - 1]||d0;

				var Q = extremum(data, pos, 20, 'Q%');

				return [
					d0['Q%'] - d1['Q%'],
					(d0.AV - d1.AV)*100/d1.AV,
					Q.max, Q.min,
					d0.V0 - d1.V0
				]
			},
		},
		{
			//name : ["拐点"],
			//key : ["EX"],
			func : function(data, pos) {
				if (null == pos) {
					pos = data.length - 1;
				}

				var t = trend(data, pos-1, 4);
				var d0 = data[pos];
				var c = (d0.LS + d0.HS)/2;
				var l = (t[0]+t[1])/2;
				if (c * l < 0) {
					return [c - l];
				}
				var p = getProbability(d0.close, d0.AV, d0.Q);
				return [0];
			}
		},
	],
	// LV3
	[
		{
			//name: ["高氏因子","高氏因子昨"],
			//key: ["GaoFactor","GaoFactor1"],
			func: function (data, pos) {
				var d0 = data[pos];
				var d1 = data[pos-1];
				var d2 = data[pos-2];

				function vol(arr, pos) {
					var d0 = arr[pos];
					var d1 = arr[pos-1];
					var d2 = arr[pos-2];

					var r1 = d0.turnover - d1.turnover;
					var r2 = d1.turnover - d2.turnover;
					if (r1 * r2 < 0) {
						return d1.turnover - ((d0.turnover+d2.turnover)/2);
					}
					return 0;
				}

				function select(arr, pos) {
					var d0 = arr[pos];
					var d1 = arr[pos-1];
					var m5 = avg(arr, pos, 5, 'close');
					var m10 = avg(arr, pos, 10, 'close');
					if ((d0.close > d0.open) && (d0.close > d1.close)
						&& (d0.close > m5) && (d0.close > m10)
						&& (d0.low < m5) && (d0.low < m10)){
						return vol(arr, pos);
					}
					return 0;
				}

				/*
				var Q = extremum(data, pos, 20, 'close');
				var Q1 = extremum(data, pos-1, 20, 'close');

				var f = (d1.turnover/d0.turnover + 1)*10 + d0.R1;
				if (Q.transactions < 15000) f = 0;
				if (Q.maxPos - pos < 0) f = 0;

				var f1 = (d2.turnover/d1.turnover + 1)*10 + d1.R1;
				if (Q1.transactions < 15000) f1 = 0;
				if (Q1.maxPos - (pos-1) < 0) f1 = 0;
				*/

				return [
					//f, f1
					cut(select(data, pos)), cut(select(data, pos-1))
				]
			},
		},
	],
];